/**
 * Collaborative Story Development Web Application (CSDApp) 
 * Copyright Anton Strack 2014
 *
 * This file is part of Collaborative Story Development Application (CSDApp).
 *
 * CSDApp is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 *
 * CSDApp is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * CSDApp. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package csdwa;

import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

/**
 * This class handles the core functional logic of the notification system.
 *
 * @author Anton Strack
 */
public class NotificationManager {

    private NotificationRecipientMapperDao nrmDao;
    private NotificationTemplateDao ntDao;
    private Connection conn;
    protected String requestResultMessage;

    public NotificationManager(Connection conn) {
        this.conn = conn;
        this.nrmDao = new NotificationRecipientMapperDao(conn);
        this.ntDao = new NotificationTemplateDao(conn);
    }

    /**
     * This method handles the processing of notification events.
     *
     * @param eventCreatorId the user id of who triggered the event.
     * @param actionId the action id of the event.
     * @param subjectId the id of the resource the event occurred on.
     * @param subjectStateId the current state id of the resource the event was
     * triggered on.
     * @param subjectResourceTypeId the resource type id of the resource the
     * action occurred on
     * @param subjectName the name of the resource
     */
    public void listen(int eventCreatorId, int actionId, int subjectId, int subjectStateId, int subjectResourceTypeId, String subjectName) {
        int templateId = this.check(actionId, subjectStateId, subjectResourceTypeId);
        if (templateId > 0) {
            int recipientCount = this.nrmDao.selectUsersByNotificationTemplateId(templateId, false);
            if (recipientCount > 0) {
                this.notify(eventCreatorId, templateId, subjectId, subjectName);
            }
        }
    }

    /**
     * This method checks the database to see if there is a notification
     * template that matches the event signature.
     *
     * @param actionId the action id of the event.
     * @param subjectStateId the current state id of the resource the event was
     * triggered on.
     * @param subjectResourceTypeId the resource type id of the resource the
     * action occurred on
     * @return the notification template id that matches the event or 0 if there
     * are no matching notification templates
     */
    public int check(int actionId, int subjectStateId, int subjectResourceTypeId) {
        int result = this.ntDao.selectNotificationTemplates(actionId, subjectStateId, subjectResourceTypeId);
        if (result > 0) {
            result = this.ntDao.getBean().getId();
        }
        return result;
    }

    /**
     * Preform the actual notification of the event to the registered users.
     *
     * @param eventCreatorId the user id of who triggered the event.
     * @param notificationTemplateId the id of the template the notification is
     * built from
     * @param subjectId the id of the resource the event occurred on.
     * @param subjectName the name of the resource
     */
    public void notify(int eventCreatorId, int notificationTemplateId, int subjectId, String subjectName) {
        Timestamp time = new Timestamp(new Date().getTime());
        Notification notification = ResourceFactory.makeNotification();
        notification.setEventCreatorId(eventCreatorId);
        notification.setNotificationDate(time);
        notification.setNotificationTypeId(notificationTemplateId);
        notification.setResourceId(subjectId);
        notification.setResourceName(subjectName);
        notification.setStateId(InfoAggregator.getInstance().getStateTypeId("unread"));
        NotificationDao nDao = new NotificationDao(conn);
        for (User user : this.nrmDao.getUserDao().getBeans()) {
            notification.setUserId(user.getId());
            if (user.getId() == eventCreatorId && this.ntDao.getBean().includeCurrentUser == false) {
                // skip the user as they don't want to be notified by events they caused
            } else {
                int result = nDao.insertBean(notification);
            }
        }
    }

    /**
     * This method is used to attach the user notifications to the request so it
     * is available to the jsp pages
     *
     * @param request the request to add the user histories to.
     * @return the request object containing the user histories with key
     * "userHistories"
     */
    public CsdwaRequest attachUserNotifications(CsdwaRequest request) {
        User user = request.getCurrentUser();
        List<Notification> userNotifications = retrieveUserNotifications(user.getId(), InfoAggregator.getInstance().getStateTypeId("unread"), false);
        request.setAttribute("userNotifications", userNotifications);
        return request;
    }

    /**
     * This method is a wrapper for retrieveUserNotifications that provides a
     * default implementation to retrieve all notifications for a user.
     *
     * @param userId the id of the user to retrieve the notifications for.
     * @return A list of notifications for the particular user
     */
    public List<Notification> retrieveUserNotifications(int userId) {
        return this.retrieveUserNotifications(userId, 0, false);// zero means get everything
    }

    /**
     * This method retrieves notifications for a particular user.
     *
     * @param userId the id of the user to retrieve the notifications for.
     * @param stateId the state of the notification to retrieve. Setting it to 0
     * means select notifications of any state.
     * @param equalling if the retrieved states should equal the indicated state
     * id or if they should not equal the indicated state id. If the state id is
     * 0, then this argument is ignored.
     * @return A list of notifications for the particular user and optionally
     * filtered by the stateId;
     */
    public List<Notification> retrieveUserNotifications(int userId, int stateId, boolean equalling) {
        NotificationDao nDao = new NotificationDao(conn);
        String max = "LIMIT " + Configuration.getRecentNotificationsMaxCount();// convert to string
        nDao.setMarker(QueryMarker.LIMIT, max);
        nDao.addUsingQueryMarker(QueryMarker.LIMIT);
        nDao.setUseRelatedMarkers(true);
        int result;
        if (stateId == 0) {
            result = nDao.selectBeansByUserId(userId);
        } else {
            result = nDao.selectBeansByUserId(userId, stateId, equalling);
        }
        if (result > 0) {
            this.ntDao.clearDaoBeans();
            this.ntDao.setUseRelatedMarkers(true);
            int result2 = this.ntDao.selectBeanById(nDao.getBean().getNotificationTypeId());
            if (result2 > 0) {
                for (Notification notification : nDao.getBeans()) {
                    notification.setTemplate(this.ntDao.getBean());
                }
                return nDao.getBeans();
            }
        }
        return null;
    }
}
